﻿<!--修改于2024-05-10 对话框弹出重新渲染表单 -->
<!--修改于2024-04-03 修正查询字段变更级联初始化-->
<style>
.query-table {
  position: relative;padding:0 10px;box-sizing: border-box;
}
  /*.query-table .el-table th {*/
  /*  background-color: rgb(245, 247, 250);*/
  /*}*/
  /*.query-table .el-table tr {*/
  /*  !*line-height: 34px;*!*/
  /*  height: 34px;*/
  /*}*/
</style>
<template>
  <div :id="id" class="query-table" v-loading="isLoading"
    :element-loading-text="loadingText">
    <el-form :key="'query-form'+timestamp" size="small" v-if="queryConditionInit&&queryFields&&queryFields.length>0" :label-width="formLabelWidth" style="box-sizing:border-box;width:100%;">
      <el-row>
      <custom-field-form-item :data="queryCondition" :fields="queryFields" columns="8">
        <div style="float: left;">
          <el-button type="primary" size="small" v-if="showQuery"  @click="loadDataList(1)">查询</el-button>
          <template v-if="appendButtonList&&appendButtonList.length>0">
            <el-button v-for="item in appendButtonList"
                       :type="item.type?item.type:'default'"
                       :key="'query-table_query_button_'+timestamp+'_'+item.name+item.text"
                       size="small" @click="handleButtonClick(item)">
              {{item.text}}
              <span v-if="item.tooltip">

                <el-tooltip class="item" :effect="item.tooltip.effect==null?'dark':item.tooltip.effect" :content="item.tooltip.content"
                            :placement="item.tooltip.placement==null?'top-start':item.tooltip.placement">
                  <i :class='item.tooltip.icon==null?"el-icon-question":item.tooltip.icon' />
                </el-tooltip>
<!--                <el-popover-->
<!--                    placement="top-start"-->
<!--                    :title="item.popover.title==null?'提示':item.popover.title"-->
<!--                    :width="item.popover.width==null?200:item.popover.width"-->
<!--                    :trigger="item.popover.trigger==null?'hover':item.popover.trigger"-->
<!--                    :content="item.popover.content">-->
<!--                 -->
<!--                </el-popover>-->
              </span>
            </el-button>


          </template>
        </div>
      </custom-field-form-item>
      </el-row>
    </el-form>
    <slot></slot>
    <record-table v-if="columns.length>0&&dataList" :ref="'query-table-body-'+timestamp" :readonly="readonly" :max-height="tableMaxHeight" :data="dataList"
                  :selectable="selectable" :show-checkbox="showCheckbox" :default-selected="defaultSelected"
                  :row-style="rowStyle" :columns="columns" :show-index="showIndex" @selection-change="handleSelectChange">
    </record-table>
    <el-pagination v-if="dataCount"
        style="text-align:center;padding-top:10px;"
        :hide-on-single-page="hidePaginationOnSinglePage"
        background
        @size-change="handlePageSizeChange"
        @current-change="loadDataList"
        :current-page="pageNo"
        :page-sizes="[10, 20, 30, 40,50,100]"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="dataCount">
    </el-pagination>
    <el-dialog v-loading="loadingInfoDetail"
               :title="dialogOperateMode=='edit'?'编辑':(dialogOperateMode=='create'?'新增':'查看')"
               :visible.sync="infoDetailDlgVisible"
               append-to-body
               :close-on-click-modal="false"
               width="50%">
      <custom-field-form :key="'info-form'+formTimestamp" :fields="detailFields" :data="this.infoDetail" columns="2" :readonly="dialogOperateMode=='view'"></custom-field-form>
      <span slot="footer" class="dialog-footer">
        <el-button type="success" v-if="dialogOperateMode!='view'"  @click="saveInfo">保存</el-button>
        <el-button  @click="infoDetailDlgVisible = false">取消</el-button>
      </span>
    </el-dialog>
  </div>

</template>

<script>
  import CustomFieldFormItem from "./custom-field-form-item";
  export default {
    name: "QueryTable",
    components: {CustomFieldFormItem},
    props: {
      readonly:{
        type:Boolean,
        default:true
      },
      //表格最大高度
      tableMaxHeight: {
        type: Number,
        default: 8000
      },
      showQuery:{
        type:Boolean,
        default:true
      },
      //表格id
      id:{
        type:String,
        default:'query-table-'+new Date().getTime()
      },
      //导出名称
      exportFileName:{
        type:String,
        default:'导出数据'
      },
      //表格列数据
      /*columns数组元素属性：
       id:字段id
       name:显示名称
       width:宽度
        align:对齐方式
        type:列类型 meta元数据，配合source使用
        source:数据来源
       */
      columns: {
        type: Array,
        default:()=>{return [];}
      },
      //基础路径，默认列表数据为 baseUrl+'/data',创建接口为 baseUrl+'/create',更新接口为 baseUrl+'/update',
      // 删除接口为 baseUrl+'/delete'，详情接口为 baseUrl+'/info/'+id
      baseUrl:{
        type:String,
        default:null,
      },
      //数据接口,优先级比baseUrl生成高
      dataUrl:{
        type:String,
        default:null
      },//数据接口,优先级比baseUrl生成高
      dataRequestMethod:{
        type:String,
        default:'get'
      },
      //删除接口,优先级比baseUrl生成高
      deleteUrl:{
        type:String,
        default:null,
      },
      //更新数据接口,优先级比baseUrl生成高
      updateUrl:{
        type:String,
        default:null,
      },
      //详情数据接口
      detailUrl:{
        type:String,
        default:null,
      },
      //创建数据接口
      createUrl:{
        type:String,
        default:null,
      },

      //每页条数
      pageSize:{
        type:Number,
        default:10
      },
      /**
       * 顶部查询字段列表。字段属性
       * name：字段名称
       * id：字段id
       * defaultValue：字段默认值
       * component:组件类型，data-select、meta-select、year-picker、date-picker、company-select，复杂配置使用对象形式，id为组件标识
       * type:数据来源
       */
      queryFields:{
        type:Array,
        default:()=>{return [];}
      },
      /**
       * 信息维护字段。字段属性
       * name：字段名称
       * id：字段id
       * defaultValue：字段默认值
       * component:组件类型，data-select、meta-select、year-picker、date-picker、company-select，复杂配置使用对象形式，id为组件标识
       * type:数据来源
       * isHide:判断是否隐藏函数
       * isDisabled:判断是否禁用函数
       */
      detailFields:{
        type:Array,
        default:()=>{return [];}
      },
      //
      /**
       * 附加按钮，包含以下属性
       * type:按钮类型
       * name:按钮名称
       * click:点击事件
       * operation:触发组件方法
       */
      appendButtons:{
        type:Array,
        default:()=>{return [];}
      },
      //只有一页时是否隐藏分页条
      hidePaginationOnSinglePage:{
        type:Boolean,
        default:false
      },
      //是否可选判断
      selectable:{
        type:Function,
        default:()=>{return true;}
      },
      //是否显示新增按钮
      creatable:{
        type:Boolean,
        default:false
      },
      //是否显示行号
      showIndex:{
        type:Boolean,
        default:false
      },
      //是否显示行号
      showCheckbox:{
        type:Boolean,
        default:false
      },
      //默认选中项
      defaultSelected:{
        type:Function,
        default:null
      },
      //数据加载后展示前处理函数
      beforeDisplayList:{
        type:Function,
        default:null
      },
      //模拟数据，用于测试
      mockData:{
        type:Array,
        default:null
      },

      //详情数据加载完成展示前
      beforeDisplayDetail:{
        type:Function,
        default:null
      },
      
      //请求返回结果后最终调用方法
      responseFinallyCallback:{
        type:Function,
        default:null
      },
      //默认查询条件
      defaultQueryParams:{
        type:Object,
        default:null
      },
      //行样式
      rowStyle:{
        type:Object,
        default:null
      },
      //详情对话框是否加载后端数据
      detailDialogLoadData:{
        type:Boolean,
        default:true
      }
    },
    data() {
      return {
        isLoading: false,
        loadingText: '正在处理...',
        formLabelWidth: '120px',
        dataList:null,//数据列表,初始值设为null，防止设为空数组加载数据后监听变动重复渲染
        queryCondition:{},//查询条件,上方查询区域值
        queryData:{},//查询数据，当前已加载数据查询条件
        //查询条件初始化完成
        queryConditionInit:false,
        pageNo:1,//当前页码
        dataCount:0,//数据总条数
        //列定义
        columnList:[],
        appendButtonList:[],
        //详情数据
        infoDetail:{},
        //详情数据对话框显示状态
        infoDetailDlgVisible:false,
        //详情数据加载状态
        loadingInfoDetail:false,
        //详情编辑状态
        dialogOperateMode:'view',
        //时间戳，用于组件key生成，防止复用或者重复渲染
        timestamp:new Date().getTime(),
        formTimestamp:new Date().getTime(),
      }
    },

    watch: {
      columns: {
        handler(val, oldVal) {
          this.init();
        },
        immediate: false,
        deep: true
      },
      appendButtons: {
        handler(val, oldVal) {
          this.initQueryAreaButtons();
        },
        // immediate: false,
        deep: true
      },
      mockData: {
        handler(val, oldVal) {
          this.loadDataList();
        },
        immediate: false,
        deep: true
      },
      queryFields: {
        handler(val, oldVal) {
          // this.queryConditionInit = false;
          this.initQueryCondition();
        },
        immediate: false,
        deep: true
      },
      defaultQueryParams: {
        handler(val, oldVal) {
          // this.loadDataList();
        },
        immediate: false,
        deep: false
      },

    },

    created: function () {
      this.init();
    },
    mounted: function () {
      this.loadDataList();
    },

    methods: {
      init() {
        this.initQueryCondition();
        if(this.columns) {
          //扫描列信息，为删除按钮绑定事件
          let columnList = [];
          for(let item of this.columns) {
            columnList.push(item);
            if(item.type!='button') {
              continue;
            }
            let buttons = [];
            if(item.children) {
              //每行按钮
              for(let btn of item.children) {
                buttons.push(btn);
                if(btn.children&&btn.children.length) {
                  //dropdown类型菜单
                  for(let subBtn of btn.children) {
                    buttons.push(subBtn);
                  }
                  btn.handleCommand = (command,row,buttons)=>{
                    for(let subBtn of buttons){
                      if(!subBtn.click) {
                        continue;
                      }
                      if(subBtn.text == command) {
                        subBtn.click(row);
                        break;
                      }
                    }
                  }
                }
              }
            }
            if(item.header&&item.header.type=='button'&&item.header.children) {
              //标题栏按钮
              for(let btn of item.header.children) {
                buttons.push(btn);
                if(btn.children&&btn.children.length) {
                  //dropdown类型菜单
                  for(let subBtn of btn.children) {
                    buttons.push(subBtn);
                  }
                  btn.handleCommand = (command,row)=>{
                    for(let subBtn of btn.children){
                      if(!subBtn.click) {
                        continue;
                      }
                      if(subBtn.text == command) {
                        subBtn.click(row);
                        break;
                      }
                    }
                  }
                }
              }
            }
            for(let btn of buttons) {
              if(btn.operation=='create') {
                //如果按钮的操作为create，则绑定新增按钮事件
                btn.click = this.openCreateDlg;
              }if(btn.operation=='delete') {
                //如果按钮的操作为delete，则绑定删除事件
                btn.click = this.deleteRow;
              } else if(btn.operation=='edit') {
                //如果按钮的操作为edit，则绑定编辑事件
                btn.click = this.openEditDlg;
              } else if(btn.operation=='view') {
                //如果按钮的操作为view，则绑定查看事件
                btn.click = this.openViewDlg;
              } else if(btn.operation=='export') {
                //如果按钮的操作为export，则绑定导出事件
                btn.click = this.exportTableData;
              }
            }
          }
        }
        this.initQueryAreaButtons();
        //初始化字典可修改状态
        if(this.detailFields&&this.detailFields.length>0) {
          for(let item of this.detailFields) {
            //如果字段可更新为false，则编辑时不可更新，默认为true
            if(item.disableOnEdit) {
              item.isDisabled = (data)=>{
                return this.dialogOperateMode == 'edit';
              }
            }
            if(item.hideOnEdit) {
              item.isHide = (data)=>{
                return this.dialogOperateMode == 'edit';
              }
            }
          }
        }
        // this.judgeLongestLabelWidth();
      },
      //初始化查询区域按钮
      initQueryCondition() {
        if(this.queryFields.length>0) {
          let map = {};
          for(let item of this.queryFields) {
            // item.show = true;
            let value = '';
            if(item.component=='input-number-range'||(item.component&&item.component.id=='input-number-range')){
              //数值范围输入框特殊处理
              value = [];
            }
            if(item.dataType=='array') {
              value = [];
            }
            if(item.defaultValue!=undefined||item.getDefaultValue) {
              if(item.getDefaultValue) {
                value = item.getDefaultValue();
              } else {
                value = item.defaultValue;
              }
            }

            map[item.id] = value;
          }
          map.pageNo = 1;
          map.pageSize = this.pageSize;
          this.queryConditionInit = true;
          this.queryCondition = map;

        }
        this.judgeLongestLabelWidth();
      },
      //初始化查询区域按钮
      initQueryAreaButtons() {
        let list = [];
        for(let btn of this.appendButtons) {
          if(btn.permission&&this.checkPermission(btn.permission)==false) {
            continue;
          }
          if(btn.isHide&&btn.isHide()){
            continue;
          }
          if(btn.operation=='create') {
            //如果按钮的操作为delete，则绑定删除事件
            btn.click = this.openCreateDlg;
          } else if(btn.operation=='export') {
            //如果按钮的操作为export，则绑定导出事件
            btn.click = this.exportTableData;
          }
          list.push(btn);
        }
        this.appendButtonList = list;
      },
      //加载数数据列表
      loadDataList(pageNo) {
        if (!this.dataUrl && !this.baseUrl) {
          if (this.mockData) {
            //假数据，用于测试
            if (this.beforeDisplayList) {
              //用于处理数据渲染前逻辑
              this.beforeDisplayList(this.mockData)
            }
            this.dataList = this.mockData;
            return;
          }
          this.$message.warning("未配置数据接口，无法加载数据")
          return;
        }

        this.isLoading = true;

        if (!pageNo) {
          pageNo = 1;
        } else {
          this.pageNo = pageNo;
        }
        this.queryCondition.pageNo = this.pageNo;
        this.queryCondition.pageSize = this.pageSize;

        let dataUrl = this.dataUrl;
        if (!dataUrl) {
          dataUrl = this.baseUrl + '/data';
        }
        //查询数据由默认参数及查询字段组成
        let queryData = {};
        if (this.defaultQueryParams) {
          for (let key in this.defaultQueryParams) {
            if (!this.defaultQueryParams[key] && this.defaultQueryParams[key] != 0) {
              //忽略空值
              continue;
            }
            queryData[key] = this.defaultQueryParams[key];
          }
        }
        for (let key in this.queryCondition) {
          if (!this.queryCondition[key] && parseInt(this.queryCondition[key]) != 0) {
            //忽略空值
            continue;
          }
          queryData[key] = this.queryCondition[key];
        }
        this.queryData = queryData;
        if (this.dataRequestMethod == 'post') {
          this.$post(dataUrl, queryData, (response) => {
            let list = response.data;
            if (this.beforeDisplayList) {
              //用于处理数据渲染前逻辑
              this.beforeDisplayList(list)
            }
            this.dataList = list;
            if(response.total) {
              this.dataCount = response.total;
            }
          }, (response) => {
            this.isLoading = false;
            if (this.responseFinallyCallback) {
              this.responseFinallyCallback(response, 'list');
            }
          });
        } else {
          this.$get(dataUrl, queryData, (response) => {
            let list = response.data;
            if (this.beforeDisplayList) {
              //用于处理数据渲染前逻辑
              this.beforeDisplayList(list)
            }
            this.dataList = list;
            this.dataCount = response.total;
          }, (response) => {
            this.isLoading = false;
            if (this.responseFinallyCallback) {
              this.responseFinallyCallback(response, 'list');
            }
          });
        }
      },

      //处理每页条数变更
      handlePageSizeChange(size){
        this.pageSize = size;
        this.loadDataList(this.pageNo);
      },
      //按钮点击响应
      handleButtonClick(button, row) {
        if (button.click) {
          button.click(row);
        }
      },
      //重新加载当前页
      reload() {
        this.loadDataList(this.pageNo);
      },
      //删除数据
      deleteRow: function(row){
        if(!this.deleteUrl&&!this.baseUrl) {
          this.$message.warning("未配置删除接口");
          return;
        }
        let id = row.id;
        let tipMsg = '确定删除该条数据?';
        if(row.name) {
          tipMsg = '该操作将删除 【' + row.name + '】 相应数据, 是否继续?';
        }
        this.$confirm(tipMsg, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          let deleteUrl = this.deleteUrl;
          if(!deleteUrl) {
            deleteUrl = this.baseUrl+'/delete';
          }
          this.isLoading = true;
          this.$post(deleteUrl+"?id="+id,{id:id},(response) => {
            this.$message.success('删除成功！');
            this.loadDataList();
          },(response)=> {
            this.isLoading = false;
            if(this.responseFinallyCallback) {
              this.responseFinallyCallback(response,'delete');
            }
          });
        }).catch(() => {
        });

      },
      judgeLongestLabelWidth: function () {
        let dataList = [];
        if(!this.queryFields) {
          return ;
        }
        for(let item of this.queryFields) {
          dataList.push(item.name);
        }
        let text = '默认字';
        for (let data of dataList) {

          if (data != undefined && data.length > text.length) {
            text = data;
          }
        }

        let array = text.split('');
        let length = 0;
        for (let char of array) {
          if (escape(char).indexOf("%u") < 0) {
            length++;
          } else {
            length += 2;
          }
        }
        this.formLabelWidth =  (length + 4) * 7+'px';
      },
      saveInfo: function () {
        const message = this.$message;
        let saveData = JSON.parse(JSON.stringify(this.infoDetail));
        for(let field of this.detailFields) {
          if(field.component == 'password'||(field.component&&field.component.id=='password')) {
            //如果组件类型是密码，则进行加密后传输
            if(saveData[field.id]) {
              let rsaPassword = this.$encryption(saveData[field.id]);
              saveData[field.id] = rsaPassword;
            }
          } else if(field.dataType=='array') {
            if(!saveData[field.id]) {
              saveData[field.id] = [];
            }
          }
        }
        if (this.dialogOperateMode=='edit') {
          if(!this.updateUrl&&!this.baseUrl) {
            message.warning("未配置更新数据接口")
            return;
          }
          let updateUrl = this.updateUrl;
          if(!updateUrl) {
            updateUrl = this.baseUrl+'/update';
          }
          this.loadingInfoDetail = true;
          this.$post(updateUrl, saveData, (response) => {
            message.success('更新成功！');
            this.loadDataList();
            this.infoDetailDlgVisible = false;
          },(response)=>{
            if(this.responseFinallyCallback) {
              this.responseFinallyCallback(response,'update');
            }
            this.loadingInfoDetail = false;
          });
        } else if(this.dialogOperateMode=='create'){
          if(!this.createUrl&&!this.baseUrl) {
            message.warning("未配置创建数据接口")
            return;
          }
          let createUrl = this.createUrl;
          if(!createUrl) {
            createUrl = this.baseUrl+'/create';
          }
          this.loadingInfoDetail = true;

          this.$post(createUrl, saveData, (response) => {
            message.success('创建成功！');
            this.loadDataList();
            this.infoDetailDlgVisible = false;
          },(response)=>{
            if(this.responseFinallyCallback) {
              this.responseFinallyCallback(response,'create');
            }
            this.loadingInfoDetail = false;
          });
        }
      },
      //清除表单验证状态
      clearFormValidate(formRef) {
        this.$nextTick(()=>{
          this.$refs[formRef].clearValidate();
        });
      },
      //打开数据编辑对话框，并加载数据
      openEditDlg(item) {
        this.formTimestamp = new Date().getTime();
        const message = this.$message;
        this.dialogOperateMode = 'edit';
        // this.clearFormValidate('info-form'+this.formTimestamp);
        if(!this.detailDialogLoadData) {
          this.loadingInfoDetail = true;
          this.infoDetailDlgVisible = true;
          let detailData = JSON.parse(JSON.stringify(item));
          if(this.beforeDisplayDetail) {
            this.beforeDisplayDetail(detailData);
          }
          this.infoDetail = detailData;
          this.loadingInfoDetail = false;
          return;
        }
        if(!this.detailUrl&&!this.baseUrl) {
          message.warning("未配置数据详情接口")
          return;
        }
        this.loadingInfoDetail = true;
        this.infoDetailDlgVisible = true;
        let detailUrl = this.detailUrl;
        if(!detailUrl) {
          detailUrl = this.baseUrl+'/info/'+item.id;
        }
        this.$get(detailUrl, {id:item.id}, (response) => {
          let detailData = response.data;
          if(this.beforeDisplayDetail) {
            this.beforeDisplayDetail(detailData);
          }
          this.infoDetail = detailData;
        }, (response) => {
          this.loadingInfoDetail = false;
          if(this.responseFinallyCallback) {
            this.responseFinallyCallback(response,'detail');
          }
        });
      },
      //打开数据查看对话框，并加载数据
      openViewDlg(item) {
        this.formTimestamp = new Date().getTime();
        const message = this.$message;
        this.loadingInfoDetail = true;
        this.dialogOperateMode = 'view';
        // this.clearFormValidate('info-form'+this.formTimestamp);
        if(!this.detailUrl&&!this.baseUrl) {
          message.warning("未配置数据详情接口")
          return;
        }
        this.infoDetailDlgVisible = true;
        let detailUrl = this.detailUrl;
        if(!detailUrl) {
          detailUrl = this.baseUrl+'/info/'+item.id;
        }
        this.$get(detailUrl, {id:item.id}, (response) => {
          let detailData = response.data;
          if(this.beforeDisplayDetail) {
            this.beforeDisplayDetail(detailData);
          }
          this.infoDetail = detailData;
        }, () => {
          this.loadingInfoDetail = false;
        });
      },
      //初始化数据详情
      initInfoDetail() {
        if(this.detailFields&&this.detailFields.length>0) {
          //初始化数据详情
          let map = {};
          for(let item of this.detailFields) {
            if(!item.id){
              continue;
            }
            let value = '';
            if(item.dataType=='array') {
              value = [];
            }
            if(item.defaultValue!=undefined||item.getDefaultValue) {
              if(item.getDefaultValue) {
                value = item.getDefaultValue();
              } else {
                value = item.defaultValue;
              }
            }
            map[item.id] = value;
          }
          this.infoDetail = map;
          for(let item of this.detailFields) {
            if (item.init) {
              item.init(this.infoDetail)
            }
          }
        }
      },
      //打开新增对话框
      openCreateDlg() {
        this.formTimestamp = new Date().getTime();
        this.initInfoDetail();
        this.dialogOperateMode = 'create';
        this.infoDetailDlgVisible = true;
        // this.clearFormValidate('info-form'+this.formTimestamp);
      },

      handleSelectChange(val) {
        this.$emit('selection-change',val)
      },
      //获取当前查询条件
      getQueryData() {
        return this.queryData;
      },
      //导出当前表格为excel文件
      exportTableData() {
        this.exportExcel(this.id,this.exportFileName);
      },
      //获取变更数据
      getChangeData() {
        return this.$refs['query-table-body-' + this.timestamp].getChangeData();
      },
      //变更查询条件
      updateQueryCondition(fieldId,value,reload){
        this.queryCondition[fieldId] = value;
        if(reload) {
          this.reload();
        }
      },
      //获取数据列表
      getDataList() {
        return this.dataList;
      },
    },

  }
</script>